package com.doit.day02

import com.doit.day01._

/**
 * 函数：一段代码逻辑的封装，为了后续的复用
 * ():函数的参数
 * {}：函数体
 * {}里面最后一行代码指的是函数的返回值
 * 没有名字的函数叫匿名函数==》一般传参的时候用
 *
 * 定义一个函数：函数体里面打印一句话，小江真帅！！！，参数列表里面啥都不要
 * 手动写出来他的类型
 *
 * 最后再来一遍：用java写一遍==》先定义一个接口，然后new 这个接口，重写里面的抽象方法(apply)=》最后调用方法
 */
object _02_函数 {
  def main(args: Array[String]): Unit = {
    println(getSum(1, 2, 3, 4))

    //getSum 是个对象名
    //(a:Int,b:Int,c:Int,d:Int)==> apply这个抽象方法的参数
    //{a+b+c+d}==> apply 方法的具体实现
    //对象调用方法的时候，因为方法名称是apply 在scala里面，apply方法可以省略
    getSum(1, 2, 3, 4)
    getSum.apply(1, 2, 3, 4)

    val abc: Int = getSum.apply(1, 2, 3, 4)


    val abd: Function4[Int, Int, Int, Int, Int] = getSum


    //函数当做参数传递
    def getFunc(a: Int, op: Int => Int) = {
      op.apply(a)
    }

    //函数当做返回值返回
    //第一用语法糖的写法，将myFunc2的类型补全
    //用java的正统写法，将这个类型补全
    val myFunc2: (Int, Int) => Int => Int = (a: Int, b: Int) => {
      val abd: Int => Int = (c: Int) => {
        a + b + c
      }
      abd
    }

    val myFunc3:Function2[Int,Int,Function1[Int,Int]] = (a: Int, b: Int) => {
      (c: Int) => {
        a + b + c
      }
    }




    //函数的本质是个啥  ==>对象嘛？接口的实现类对象

    //调用函数运行的时候，本质上是对象调用apply方法

    //定义函数的时候，本质上相当于在创建这个接口的实现类对象，然后重写里面的抽象方法(apply方法)

    def hhh(p: Person) = {
      println("你真帅")
    }



    //函数的本质就是一个对象
    val abcd = (a: Int, b: Function1[Int, Int]) => {
      b(a)
    }

    //    abcd

    def abcc(a: Int, b: Int) = {
      a + b
    }
    //方法可以转变成函数
    //    val res2: (Int, Int) => Int = abcc _
  }

  val getSum: Function4[Int, Int, Int, Int, Int] = (a: Int, b: Int, c: Int, d: Int) => {
    a + b + c + d
  }


  val add: (Int, Int) => Int = (a: Int, b: Int) => {
    a + b
  }

  val add1: (Int, String) => String = (a: Int, b: String) => {
    a + b + ""
  }


  val getMax = (a: Int, b: Int, c: Int) => {
    var max = a
    if (max < b) max = b
    if (max < c) max = c
    max
  }
}
